/**
 * @file Config.cpp
 * @author  haifeng (haifengxiao@icloud.com)
 * @brief
 * @version 0.1
 * @date 2021-07-18
 *
 * @copyright Copyright (c) 2021
 *
 */

#include <list>
#include "Config.h"
#include "ConfigVal.h"

namespace Chen {
    namespace Conf {

        Config::ConfigMap Config::s_datas;

        ConfigValBase::ptr Config::LookupBase(const std::string& name) {
            auto it = s_datas.find(name);
            return it == s_datas.end() ? nullptr : it->second;
        }

        static void ListAllMenber(const std::string& prefix,
            const YAML::Node& node,
            std::list<std::pair<std::string, const YAML::Node>>& output)     {
            if (prefix.find_first_not_of("abcdefghijklmnopqrstuvwxyz._012345678")
                != std::string::npos)         {
                std::cout << "invaild";
                return;
            }
            output.push_back(std::make_pair(prefix, node));
            if (node.IsMap()) {
                for (auto it = node.begin();
                    it != node.end();it++)             {
                    ListAllMenber(prefix.empty() ? it->first.Scalar() :
                        prefix + "." + it->first.Scalar(), it->second, output);
                }
            }
        }

        void Config::LoadFromYaml(const YAML::Node& root) {
            std::list<std::pair<std::string, const YAML::Node>> all_nodes;
            ListAllMenber("", root, all_nodes);

            for (auto& node : all_nodes) {
                std::string key = node.first;
                if (key.empty()) {
                    continue;
                }

                std::transform(key.begin(), key.end(), key.begin(), ::tolower);
                Chen::Conf::ConfigValBase::ptr val = LookupBase(key);

                if (val != nullptr) {
                    if (node.second.IsScalar()) {
                        val->fromString(node.second.Scalar());
                    }
                    else {
                        std::stringstream ss;
                        ss << node.second;
                        val->fromString(ss.str());
                    }
                }
            }
        }

    }//namespace Conf
}//namespace Chen
